package com.atguigu.tingshu.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.common.constant.RabbitConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.MongoUtil;
import com.atguigu.tingshu.model.user.UserListenProcess;
import com.atguigu.tingshu.user.service.UserListenProcessService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.user.UserListenProcessVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserListenProcessServiceImpl implements UserListenProcessService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public BigDecimal getTrackBreakSecond(Long trackId) {

        // 获取登录状态
        Long userId = AuthContextHolder.getUserId();
        if (userId == null) {
            return new BigDecimal(0);
        }

        // 计算当前用户的播放进度在那个集合中
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        // 根据userId和声音id查询播放进度
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(Query.query(Criteria
                        .where("userId").is(userId)
                        .and("trackId").is(trackId)),
                UserListenProcess.class, collectionName);
        if (userListenProcess == null) {
            return new BigDecimal(0);
        }

        return userListenProcess.getBreakSecond();
    }

    @Override
    public void updateListenProcess(UserListenProcessVo userListenProcessVo) {

        Long trackId = userListenProcessVo.getTrackId();

        Long userId = AuthContextHolder.getUserId();
        if (userId == null) {
            return;
        }

        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(Query.query(Criteria
                        .where("userId").is(userId)
                        .and("trackId").is(trackId)),
                UserListenProcess.class, collectionName);
        if (userListenProcess == null) {
            // 新增播放进度
            userListenProcess = new UserListenProcess();
            BeanUtils.copyProperties(userListenProcessVo, userListenProcess);
            userListenProcess.setUserId(userId);
            userListenProcess.setIsShow(1);
            userListenProcess.setCreateTime(new Date());
            userListenProcess.setUpdateTime(userListenProcess.getCreateTime());
        } else {
            // 更新播放进度
            userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            userListenProcess.setUpdateTime(new Date());
        }
        // 更新或者新增
        this.mongoTemplate.save(userListenProcess, collectionName);

        // 验证四个一：同一个用户同一个声音同一天只统计一次
        String key = RedisConstant.USER_LISTEN_PROCESS_PREFIX + userId;
        Boolean flag = this.redisTemplate.opsForValue().getBit(key, trackId);
        if (flag) {
            return;
        }
        // 如果没有统计过则进行统计，首先先标记为已统计，并且设置过期时间是第二天凌晨
        this.redisTemplate.opsForValue().setBit(key, trackId, true);
        this.redisTemplate.expire(key, this.getExpireTime(), TimeUnit.MILLISECONDS);

        // 发送消息给RabbitMQ进行播放量的统计
        TrackStatMqVo statMqVo = new TrackStatMqVo();
        statMqVo.setAlbumId(userListenProcessVo.getAlbumId());
        statMqVo.setTrackId(userListenProcessVo.getTrackId());
        statMqVo.setCount(1);
        statMqVo.setStatType(SystemConstant.TRACK_STAT_PLAY);
        statMqVo.setBusinessNo(IdWorker.getIdStr()); // 防重复消费的唯一标识
        this.rabbitTemplate.convertAndSend(RabbitConstant.USER_EXCHANGE, RabbitConstant.TRACK_STAT_RK, JSON.toJSONString(statMqVo));
    }

    @Override
    public Map<String, Long> getLatelyTrack() {

        Map<String, Long> map = new HashMap<>();

        Long userId = AuthContextHolder.getUserId();
        if (userId == null) {
            // 返回推广的声音
            map.put("trackId", 51944L);
            map.put("albumId", 1604L);
            return map;
        }

        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(Query.query(Criteria.where("userId").is(userId))
                        .with(Sort.by(Sort.Order.desc("updateTime")))
                        .limit(1),
                UserListenProcess.class, collectionName);
        if (userListenProcess == null){
            // 返回推广的声音
            map.put("trackId", 51944L);
            map.put("albumId", 1604L);
            return map;
        }

        // 返回推广的声音
        map.put("trackId", userListenProcess.getTrackId());
        map.put("albumId", userListenProcess.getAlbumId());

        return map;
    }

    private long getExpireTime() {
        LocalDateTime endTime = LocalDateTime.of(LocalDate.now().plusDays(1), LocalTime.MIN);
        return ChronoUnit.MILLIS.between(LocalDateTime.now(), endTime);
    }
}
